package com.learn.service.impl;

import com.learn.base.BusinessResultUtil;
import com.learn.base.R;
import com.learn.config.JwtConfig;
import com.learn.constant.OperatorTokenConstants;
import com.learn.dto.system.base.CacheTokenInfo;
import com.learn.emuns.LearnResultEnums;
import com.learn.service.AdminTokenService;
import com.learn.utils.JwtUtil;
import com.learn.utils.RedisUtils;
import io.jsonwebtoken.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

/**
 * <一句话功能简述> <功能详细描述>
 *
 * @author yaoqihui
 * @version 2025/3/28
 * @see [相关类/方法]
 * @since [learn-platform]
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class AdminTokenServiceImpl implements AdminTokenService
{

	private final JwtConfig jwtConfig;
	private final RedisUtils redisUtils;

	/**
	 * 验证管理后台token
	 *
	 * @param applyType   token类型
	 * @param accessToken accessToken
	 * @param uri         接口请求uri
	 * @param method      接口请求方法，比如GET、POST
	 * @return 验证结果，若验证成功会返回成功的R
	 */
	@Override
	public R<Boolean> validateAdminJwt (String applyType, String accessToken, String uri, String method)
	{
		JwtConfig.TokenConfig adminTokenConfig = jwtConfig.getAdminConfig ();

		// 0、比对applyType
		if (StringUtils.isNotEmpty (applyType) && ! adminTokenConfig.getApplyType ().equals (applyType))
		{
			return BusinessResultUtil.build (LearnResultEnums.ILLEGAL_TOKEN.getStatus (),
					LearnResultEnums.ILLEGAL_TOKEN.getErrMsg (), false);
		}
		// 1、解析accessToken
		Claims claims;
		String accessTokenOriToken;
		String operatorId;
		String channel;
		try
		{
			claims = JwtUtil.parseToken (accessToken, jwtConfig.getKey ());
			accessTokenOriToken = claims.get (OperatorTokenConstants.ORI_TOKEN, String.class);
			operatorId = claims.get (OperatorTokenConstants.OPERATOR_ID, String.class);
			channel = claims.get (OperatorTokenConstants.CHANNEL, String.class);
			if (accessTokenOriToken == null || operatorId == null || channel == null)
			{
				log.error (
						"Failed to verify operator access token!accessTokenOriToken or operatorId or channel is null!operatorId={} channel={}",
						operatorId, channel);
				return BusinessResultUtil.build (LearnResultEnums.ILLEGAL_TOKEN.getStatus (),
						LearnResultEnums.ILLEGAL_TOKEN.getErrMsg (), false);
			}
		}
		catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | SignatureException |
			   IllegalArgumentException e)
		{
			log.error ("Failed to verify operator access token!parseToken catch en exception: ", e);
			return BusinessResultUtil.build (LearnResultEnums.ILLEGAL_TOKEN.getStatus (),
					LearnResultEnums.ILLEGAL_TOKEN.getErrMsg (), false);
		}

		// 2、redis中查询token信息是否存在
		String accessTokenKey = String.format (adminTokenConfig.getAccessTokenKeyFormat (), operatorId, channel);
		CacheTokenInfo cacheTokenInfo = (CacheTokenInfo) redisUtils.get (accessTokenKey);
		if (cacheTokenInfo == null || ! accessTokenOriToken.equals (cacheTokenInfo.getOriginToken ()))
		{
			log.error ("Failed to verify operator access token!The operator token has expired.operatorId={}",
					operatorId);
			return BusinessResultUtil.build (LearnResultEnums.ILLEGAL_TOKEN.getStatus (),
					LearnResultEnums.ILLEGAL_TOKEN.getErrMsg (), false);
		}
		return BusinessResultUtil.buildSuccess (true);
	}
}